package com.ruoyi.standingbook.sanitationvehicle.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.BeanCopyUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.standingbook.sanitationvehicle.domain.SanitationVehicle;
import com.ruoyi.standingbook.sanitationvehicle.domain.SanitationVehicleBill;
import com.ruoyi.standingbook.sanitationvehicle.domain.bo.SanitationVehicleBillBo;
import com.ruoyi.standingbook.sanitationvehicle.domain.vo.BillSendBean;
import com.ruoyi.standingbook.sanitationvehicle.domain.vo.SanitationVehicleBillVo;
import com.ruoyi.standingbook.sanitationvehicle.domain.vo.SanitationVehiclePicVo;
import com.ruoyi.standingbook.sanitationvehicle.domain.vo.SanitationVehicleVo;
import com.ruoyi.standingbook.sanitationvehicle.mapper.SanitationVehicleBillMapper;
import com.ruoyi.standingbook.sanitationvehicle.service.ISanitationVehicleBillService;
import com.ruoyi.standingbook.sanitationvehicle.service.ISanitationVehicleService;
import com.ruoyi.standingbook.v2toilet.ToiletConst;
import com.ruoyi.standingbook.v2toilet.bill.BillFlow;
import com.ruoyi.standingbook.v2toilet.enums.ItemStatusEnum;
import com.ruoyi.standingbook.v2toilet.mapper.ApiLogMapper;
import com.ruoyi.stat.toilet.logic.HttpLogic;
import com.ruoyi.system.service.ISysConfigService;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 环卫作业车-异常工单Service业务层处理
 *
 * @author lq
 * @date 2024-01-07
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class SanitationVehicleBillServiceImpl implements ISanitationVehicleBillService {
	private final ApiLogMapper apiLogMapper;
	private final SanitationVehicleBillMapper baseMapper;

	private final ISysConfigService configService;

	@SuppressWarnings("unused")
	private final ISanitationVehicleService sanitationVehicleService;

	/**
	 * 查询V2市政公厕管养-异常工单
	 */
	@Override
	public SanitationVehicleBillVo queryById(String id) {
		return baseMapper.selectVoById(id);
	}

	@Override
	public SanitationVehicleBillVo queryByFlowCode(ItemStatusEnum commit, String code) {
		SanitationVehicleBillBo bo = new SanitationVehicleBillBo();
		bo.setFlowCode(code);
		// bo.setStatus(ToiletConst.BILL_COMMIT);
		bo.setStatus(commit.intCode);
		bo.setModified(ToiletConst.MODIFY_NOT);
		LambdaQueryWrapper<SanitationVehicleBill> lqw = Wrappers.lambdaQuery();
		lqw.eq(Objects.nonNull(bo.getFlowCode()), SanitationVehicleBill::getFlowCode, bo.getFlowCode());
		lqw.eq(Objects.nonNull(bo.getStatus()), SanitationVehicleBill::getStatus, bo.getStatus());
		lqw.eq(Objects.nonNull(bo.getModified()), SanitationVehicleBill::getModified, bo.getModified());
		return baseMapper.selectVoOne(lqw);
	}

	/**
	 * 查询V2市政公厕管养-异常工单列表
	 */
	@Override
	public TableDataInfo<SanitationVehicleBillVo> queryPageList(SanitationVehicleBillBo bo, PageQuery pageQuery) {
		LambdaQueryWrapper<SanitationVehicleBill> lqw = buildQueryWrapper(bo);
		Page<SanitationVehicleBillVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
		return TableDataInfo.build(result);
	}

	/**
	 * 查询V2市政公厕管养-异常工单列表
	 */
	@Override
	public List<SanitationVehicleBillVo> queryList(SanitationVehicleBillBo bo) {
		LambdaQueryWrapper<SanitationVehicleBill> lqw = buildQueryWrapper(bo);
		lqw.eq(Objects.nonNull(bo.getSanitationVehicleId()), SanitationVehicleBill::getSanitationVehicleId, bo.getSanitationVehicleId());
		lqw.orderByAsc(SanitationVehicleBill::getStatus);
		return baseMapper.selectVoList(lqw);
	}

	@Override
	public SanitationVehicleBillVo queryOne(SanitationVehicleBillBo bo) {

		return baseMapper.queryOne(bo);
	}

	private LambdaQueryWrapper<SanitationVehicleBill> buildQueryWrapper(SanitationVehicleBillBo bo) {
		LambdaQueryWrapper<SanitationVehicleBill> lqw = Wrappers.lambdaQuery();
		lqw.eq(bo.getSanitationVehicleId() != null, SanitationVehicleBill::getSanitationVehicleId,
				bo.getSanitationVehicleId());
		lqw.eq(StringUtils.isNotBlank(bo.getItem()), SanitationVehicleBill::getItem, bo.getItem());
		lqw.eq(Objects.nonNull(bo.getStatus()), SanitationVehicleBill::getStatus, bo.getStatus());
		lqw.orderByAsc(SanitationVehicleBill::getCheckDate);

		return lqw;
	}

	/**
	 * 新增V2市政公厕管养-异常工单
	 */
	@Override
	public Boolean insertByBo(SanitationVehicleBillBo bo) {
		SanitationVehicleBill add = BeanUtil.toBean(bo, SanitationVehicleBill.class);
		validEntityBeforeSave(add);
		boolean flag = baseMapper.insert(add) > 0;
		if (flag) {
			bo.setId(add.getId());
		}
		return flag;
	}

	/**
	 * 修改V2市政公厕管养-异常工单
	 */
	@Override
	public Boolean updateByBo(SanitationVehicleBillBo bo) {
		SanitationVehicleBill update = BeanUtil.toBean(bo, SanitationVehicleBill.class);
		validEntityBeforeSave(update);
		return baseMapper.updateById(update) > 0;
	}

	/**
	 * 保存前的数据校验
	 */
	private void validEntityBeforeSave(SanitationVehicleBill entity) {
		// TODO 做一些数据校验,如唯一约束
	}

	/**
	 * 批量删除V2市政公厕管养-异常工单
	 */
	@Override
	public Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid) {
		if (isValid) {
			// TODO 做一些业务上的校验,判断是否需要校验
		}
		// return baseMapper.deleteBatchIds(ids) > 0;
		return baseMapper.realDelByIds(ids) > 0;
	}

	@Override
	public Boolean batchInsertByBo(List<SanitationVehicleBillBo> bills) {
		List<SanitationVehicleBill> list = BeanCopyUtils.copyList(bills, SanitationVehicleBill.class);
		return baseMapper.insertBatch(list);
	}

	@Override
	public Boolean batchInsertOrUpdate(List<SanitationVehicleBillBo> bills) {
		List<SanitationVehicleBill> list = BeanCopyUtils.copyList(bills, SanitationVehicleBill.class);
		return baseMapper.insertOrUpdateBatch(list);
	}

	@Override

	public List<String> listChangeInfo(Map<String, Object> map) {
		return this.baseMapper.listChangeInfo(map);
	}

	@Override
	public int updateByFlowCode(ItemStatusEnum commit, List<String> ids) {
		return updateByFlowCode(commit, ids, null, null);
	}

	private int updateByFlowCode(ItemStatusEnum commit, List<String> ids, String discoverer, String processors) {
		Map<String, Object> query = new HashMap<>();
		query.put("status", commit.intCode);
		query.put("modified", ToiletConst.MODIFY_NOT);

		query.put("ids", ids);
		
		if (StringUtils.isNotBlank(discoverer) || StringUtils.isNotBlank(processors)) {
			JSONObject obj = new JSONObject();
			
			String time = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
			if (StringUtils.isNotBlank(discoverer)) {
				obj.set("1", new BillFlow(discoverer, time, true));
			} else {
				obj.set("1", new BillFlow());
			}
		
			if (StringUtils.isNotBlank(processors)) {
				obj.set("2", new BillFlow(processors, time, true));
			} else {
				obj.set("2", new BillFlow());
			}
			
			obj.set("3", new BillFlow("", "", false));
			
			query.put("flowData", JSONUtil.toJsonStr(obj));
		}
		
		return this.baseMapper.updateByFlowCode(query);
	}

	@Override
	public int updateByFlowCode(ItemStatusEnum commit, int modified, List<String> ids) {
		Map<String, Object> query = new HashMap<>();
		query.put("status", commit.intCode);
		query.put("modified", modified);

		query.put("ids", ids);
		System.out.println(query.get("ids"));
		return this.baseMapper.updateByFlowCode(query);
	}

	@Override
	public SanitationVehicleBillVo flowData(SanitationVehicleBillBo bo) {

		List<SanitationVehicleBillVo> bills = this.queryList(bo);
		if (bills.isEmpty()) {// 假的老数据
			SanitationVehicleBillVo empVo = new SanitationVehicleBillVo();
			Map<String, BillFlow> flowMap = new HashMap<>();
			flowMap.put("1", new BillFlow());
			flowMap.put("2", new BillFlow());
			flowMap.put("3", new BillFlow());
			empVo.setFlowData(JSONUtil.toJsonStr(flowMap));
			return empVo;
		}
		return bills.get(0);

	}

	public R<String> sendBills(String batchNo) {
		SanitationVehicleBillBo billBo = new SanitationVehicleBillBo(ItemStatusEnum.ERR);
		billBo.setBatchNo(batchNo);
		
		// 找到错的
		List<BillSendBean> pullData = querySendValue(billBo);
		if (pullData.isEmpty()) {
			return R.ok();
		}
		
		// 符合条件的流水号
		List<String> flowCodes = pullData.stream().map(BillSendBean::getFlowCode).collect(Collectors.toList());// ID集合
		// 按厕所分组
		Map<String, List<BillSendBean>> groupMap = pullData.stream()
				.collect(Collectors.groupingBy(BillSendBean::getSanitationVehicleId, Collectors.toList()));
		Set<String> keys = groupMap.keySet();
		Map<String, Object> issues = new HashMap<>();
		List<Map<String, Object>> items = new ArrayList<>();

		String discoverer = null;
		for (String key : keys) {
			Map<String, Object> regions = new HashMap<>();
			BillSendBean data = groupMap.get(key).get(0);
			regions.put("place_name", data.getLicensePlateNo());
			regions.put("inspection_time", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
			regions.put("inspection_username", data.getCurrUser());
			discoverer = data.getCurrUser();
			regions.put("issue", groupMap.get(key));
			items.add(regions);
			issues.put("project_name", data.getProjectName());
		}
		issues.put("issue_list", items);
		String sendData = JSONUtil.toJsonStr(issues);
		log.info("api.bill.send >>>>>{}", sendData);
		String uuid = UUID.randomUUID().toString();
		this.saveApiLog("SanitationVehicleBillServiceImpl.sendBills", true, uuid + ":" + sendData);
		JSONObject respData;
		Integer code;
		String url = "/elec/importSanitationTrucks";
		try {
			String response = HttpLogic.postBody(configService, url, sendData);
			respData = JSONUtil.parseObj(response);
			log.info("response >>>>>{}", response);
			code = respData.get("code", Integer.class, true);
			String processors = respData.get("data", String.class, true);
			// 记录下返回结果
			if (code == 200) {
				// 更新表，设置状态为提交 同时设定重复导入后 不可以更新
				updateByFlowCode(ItemStatusEnum.COMMIT, flowCodes, discoverer, processors);
				
				return R.ok();
			} else {
				this.saveApiLog("SanitationVehicleBillServiceImpl.receiceBills", false, uuid + ":" + respData.toString());
				return R.fail(String.format("异常工单创建失败，失败原因：%s", processors));
			}
		} catch (Exception e) {
			e.printStackTrace();
			this.saveApiLog("SanitationVehicleBillServiceImpl.sendBills", false, uuid + ":" + e.getMessage());
			return R.fail(String.format("异常工单创建失败，失败原因：%s", e.getMessage()));
		}
	}

	@Override
	public List<BillSendBean> querySendValue(SanitationVehicleBillBo queryBo) {
		if (Objects.isNull(queryBo)) {
			queryBo = new SanitationVehicleBillBo(ItemStatusEnum.ERR);
		}
		if (Objects.isNull(queryBo.getStatus()))
			queryBo.setStatus(ItemStatusEnum.ERR.intCode);
        
        LambdaQueryWrapper<SanitationVehicleBill> lqw = Wrappers.lambdaQuery();
        
		lqw.eq((queryBo.getStatus() != null),
				SanitationVehicleBill::getStatus, queryBo.getStatus());
		lqw.eq((queryBo.getBatchNo() != null),
				SanitationVehicleBill::getBatchNo, queryBo.getBatchNo());		
		
		List<SanitationVehicleBill> billList = this.baseMapper.selectList(lqw);
		
		List<BillSendBean> billSendBeanList = new ArrayList<>();
		
		billList.forEach(e->{
            BillSendBean billSendBean = new BillSendBean();
            
            BeanUtils.copyProperties(e, billSendBean, "item");
            
            billSendBeanList.add(billSendBean);
        });
		
		return billSendBeanList;
	}

	private void saveApiLog(String callMethod, boolean out, String body) {
		// (id,create_time,title,data) values (#{id},#{time},#{title},#{data})
		String prefix = DateUtil.now();
		prefix = prefix.concat("-").concat(out ? "SEND" : "RECEIVE");
		log.info("length:-->prefix:{}，body:{}", prefix.length(), body.length());
		Map<String, Object> data = new HashMap<>();
		data.put("id", IdUtil.fastSimpleUUID());
		data.put("time", new Date());
		data.put("title", prefix.concat(callMethod));
		data.put("url", "");
		data.put("params", "");
		data.put("data", body);

		apiLogMapper.saveApiLog(data);
	}
}
